package com.bifang.core.oplog.integration.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.bifang.common.constant.enums.common.BoolEnum;
import com.bifang.common.constant.enums.common.FuncTypeEnum;
import com.bifang.common.exception.AppException;
import com.bifang.common.vo.operation.OperationDetailVO;
import com.bifang.common.vo.operation.OperationPeriodInitVO;
import com.bifang.common.vo.operation.OperationPeriodQueryVO;
import com.bifang.common.vo.operation.OperationPeriodVO;
import com.bifang.common.vo.operation.OperationSaveVO;
import com.bifang.common.annotations.ApiService;
import com.bifang.common.annotations.OpApi;
import com.bifang.core.dao.model.OperationPeriod;
import com.bifang.core.dao.service.OperationPeriodService;
import com.bifang.core.dict.integration.DictIntegration;
import com.bifang.core.oplog.integration.OperationPeriodIntegration;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

@Service
@ApiService(funcCode = "OPPERIOD", title = "操作期服务")
public class OperationPeriodIntegrationImpl implements OperationPeriodIntegration {
    @Autowired OperationPeriodService operationPeriodService;
    @Autowired DictIntegration dictIntegration;

    @Override
    public OperationPeriodVO getCurrentByOperating(String operating) {
        Date currentTime = new Date();
        QueryWrapper<OperationPeriod> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .lambda()
                .eq(OperationPeriod::getDel, BoolEnum.FALSE.getType())
                .eq(OperationPeriod::getOperating, operating)
                .le(OperationPeriod::getBegTime, currentTime)
                .ge(OperationPeriod::getEndTime, currentTime);
        try {
            OperationPeriod operationPeriod = operationPeriodService.getOne(queryWrapper);
            if (operationPeriod == null) {
                return null;
            }
            return Convert.convert(OperationPeriodVO.class, operationPeriod);
        } catch (Exception e) {
            e.printStackTrace();
            throw new AppException("数据异常：同一时间存在多条操作期");
        }
    }

    @Override
    @OpApi(funcCode = "OPPERIOD0001", title = "操作期列表查询", funcType = FuncTypeEnum.query)
    public List<OperationPeriodVO> getList(OperationPeriodQueryVO vo) {
        QueryWrapper<OperationPeriod> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .lambda()
                .eq(OperationPeriod::getOperating, vo.getOperating())
                .eq(OperationPeriod::getPeriodYear, vo.getPeriodYear());
        if (StringUtils.isNotBlank(vo.getAreaCode())) {
            queryWrapper.lambda().eq(OperationPeriod::getAreaCode, vo.getAreaCode());
        } else {
            queryWrapper.lambda().isNull(OperationPeriod::getAreaCode);
        }
        if (StringUtils.isNotBlank(vo.getOrgId())) {
            queryWrapper.lambda().eq(OperationPeriod::getOrgId, vo.getOrgId());
        } else {
            queryWrapper.lambda().isNull(OperationPeriod::getOrgId);
        }
        if (StringUtils.isNotBlank(vo.getClientId())) {
            queryWrapper.lambda().eq(OperationPeriod::getClientId, vo.getClientId());
        } else {
            queryWrapper.lambda().isNull(OperationPeriod::getClientId);
        }
        if (vo.getPeriodSameId() != null) {
            queryWrapper.lambda().eq(OperationPeriod::getPeriodSameId, vo.getPeriodSameId());
        }
        if (vo.getPeriodId() != null) {
            queryWrapper.lambda().eq(OperationPeriod::getPeriodId, vo.getPeriodId());
        }
        if (vo.getYm() != null) {
            queryWrapper.lambda().eq(OperationPeriod::getYm, vo.getYm());
        }
        List<OperationPeriod> list = operationPeriodService.list(queryWrapper);
        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<>();
        }
        List<OperationPeriodVO> voList = new ArrayList<>();
        for (OperationPeriod operationPeriod : list) {
            OperationPeriodVO operationPeriodVO =
                    Convert.convert(OperationPeriodVO.class, operationPeriod);
            setDict(operationPeriodVO);
            voList.add(operationPeriodVO);
        }
        return voList;
    }

    @Override
    @OpApi(funcCode = "OPPERIOD0002", title = "操作期列表数据保存", funcType = FuncTypeEnum.edit)
    public List<OperationPeriodVO> save(OperationSaveVO vo) {
        int i = 0;
        for (OperationPeriodVO operationPeriodVO : vo.getList()) {
            // 校验是否重复日期
            if (StringUtils.isBlank(operationPeriodVO.getOperating())) {
                throw new AppException("操作期规则不能为空");
            }
            //            if (operationPeriodVO.getYm() == null) {
            //                throw new AppException("业务年月不能为空");
            //            }
            if (operationPeriodVO.getPeriodYear() == null) {
                throw new AppException("所属年度不能为空");
            }
            if (operationPeriodVO.getBegTime() == null) {
                throw new AppException("开始时间不能为空");
            }
            if (operationPeriodVO.getEndTime() == null) {
                throw new AppException("结束时间不能为空");
            }
            Long startTime = operationPeriodVO.getBegTime().getTime();
            Long endTime = operationPeriodVO.getEndTime().getTime();
            if (startTime - endTime > 0) {
                throw new AppException("开始时间不能大于结束时间");
            }
            int j = 0;
            for (OperationPeriodVO opVO : vo.getList()) {
                if (i != j) {
                    if (opVO.getBegTime().getTime() - startTime < 0
                            && opVO.getEndTime().getTime() - startTime > 0) {
                        throw new AppException("时间段重复，请检查（" + i + "," + j + ")");
                    }
                    if (opVO.getBegTime().getTime() - startTime > 0
                            && opVO.getBegTime().getTime() - endTime < 0) {
                        throw new AppException("时间段重复，请检查（" + i + "," + j + ")");
                    }
                }
                j++;
            }
            i++;
            OperationPeriod operationPeriod =
                    Convert.convert(OperationPeriod.class, operationPeriodVO);
            operationPeriodService.saveOrUpdate(operationPeriod);
            operationPeriodVO.setPeriodId(operationPeriod.getPeriodId());
        }

        return vo.getList();
    }

    @Override
    @OpApi(funcCode = "OPPERIOD0003", title = "操作期列表单条新增", funcType = FuncTypeEnum.insert)
    @Transactional
    public OperationPeriodVO add(OperationPeriodVO vo) {
        OperationPeriod operationPeriod = Convert.convert(OperationPeriod.class, vo);
        checkTime(vo);
        operationPeriodService.save(operationPeriod);
        if (operationPeriod.getPeriodSameId() == null) {
            operationPeriod.setPeriodSameId(operationPeriod.getPeriodId());
            vo.setPeriodSameId(operationPeriod.getPeriodId());
        }
        vo.setPeriodId(operationPeriod.getPeriodId());
        operationPeriodService.updateById(operationPeriod);
        return vo;
    }

    private void checkTime(OperationPeriodVO vo) {
        Long startTime = vo.getBegTime().getTime();
        Long endTime = vo.getEndTime().getTime();
        if (startTime - endTime > 0) {
            throw new AppException("开始时间不能大于结束时间");
        }
        OperationPeriodQueryVO queryVO = Convert.convert(OperationPeriodQueryVO.class, vo);
        queryVO.setPeriodId(null);
        queryVO.setPeriodSameId(null);
        queryVO.setYm(null);
        List<OperationPeriodVO> list = this.getList(queryVO);
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        for (OperationPeriodVO opVO : list) {
            if (vo.getPeriodId() == null || vo.getPeriodId() - opVO.getPeriodId() != 0) {
                if (opVO.getBegTime().getTime() - startTime < 0
                        && opVO.getEndTime().getTime() - startTime > 0) {
                    throw new AppException("时间段重复，请检查");
                }
                if (opVO.getBegTime().getTime() - startTime > 0
                        && opVO.getBegTime().getTime() - endTime < 0) {
                    throw new AppException("时间段重复，请检查");
                }
            }
        }
    }

    @Override
    @OpApi(funcCode = "OPPERIOD0004", title = "操作期列表单条修改", funcType = FuncTypeEnum.edit)
    public OperationPeriodVO edit(OperationPeriodVO vo) {
        OperationPeriod old = operationPeriodService.getById(vo.getPeriodId());
        if (old == null) {
            throw new AppException("需要修改的业务期数据不存在");
        }
        checkTime(vo);
        OperationPeriod operationPeriod = Convert.convert(OperationPeriod.class, vo);
        operationPeriodService.updateById(operationPeriod);
        return vo;
    }

    @Override
    @OpApi(funcCode = "OPPERIOD0005", title = "操作期列表单条删除", funcType = FuncTypeEnum.delete)
    public void del(OperationDetailVO vo) {
        OperationPeriod old = operationPeriodService.getById(vo.getPeriodId());
        if (old == null) {
            throw new AppException("需要删除的业务期数据不存在");
        }
        operationPeriodService.removeById(vo.getPeriodId());
    }

    @Override
    @OpApi(funcCode = "OPPERIOD0006", title = "操作期列表按年度和类型清空", funcType = FuncTypeEnum.delete)
    public void clearAll(OperationPeriodQueryVO vo) {
        QueryWrapper<OperationPeriod> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .lambda()
                .eq(OperationPeriod::getOperating, vo.getOperating())
                .eq(OperationPeriod::getPeriodYear, vo.getPeriodYear());
        if (StringUtils.isNotBlank(vo.getAreaCode())) {
            queryWrapper.lambda().eq(OperationPeriod::getAreaCode, vo.getAreaCode());
        } else {
            queryWrapper.lambda().isNull(OperationPeriod::getAreaCode);
        }
        if (StringUtils.isNotBlank(vo.getOrgId())) {
            queryWrapper.lambda().eq(OperationPeriod::getOrgId, vo.getOrgId());
        } else {
            queryWrapper.lambda().isNull(OperationPeriod::getOrgId);
        }
        if (StringUtils.isNotBlank(vo.getClientId())) {
            queryWrapper.lambda().eq(OperationPeriod::getClientId, vo.getClientId());
        } else {
            queryWrapper.lambda().isNull(OperationPeriod::getClientId);
        }
        operationPeriodService.remove(queryWrapper);
    }

    @Override
    @OpApi(funcCode = "OPPERIOD0007", title = "操作期列表初始化", funcType = FuncTypeEnum.edit)
    public List<OperationPeriodVO> init(OperationPeriodInitVO vo) {
        QueryWrapper<OperationPeriod> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .lambda()
                .eq(OperationPeriod::getOperating, vo.getOperating())
                .eq(OperationPeriod::getPeriodYear, vo.getPeriodYear());
        if (StringUtils.isNotBlank(vo.getAreaCode())) {
            queryWrapper.lambda().eq(OperationPeriod::getAreaCode, vo.getAreaCode());
        } else {
            queryWrapper.lambda().isNull(OperationPeriod::getAreaCode);
        }
        if (StringUtils.isNotBlank(vo.getOrgId())) {
            queryWrapper.lambda().eq(OperationPeriod::getOrgId, vo.getOrgId());
        } else {
            queryWrapper.lambda().isNull(OperationPeriod::getOrgId);
        }
        if (StringUtils.isNotBlank(vo.getClientId())) {
            queryWrapper.lambda().eq(OperationPeriod::getClientId, vo.getClientId());
        } else {
            queryWrapper.lambda().isNull(OperationPeriod::getClientId);
        }
        long count = operationPeriodService.count(queryWrapper);
        if (count > 0) {
            throw new AppException("该操作期在年度" + vo.getPeriodYear() + "已存在数据,请先清空后再初始化");
        }
        Integer startYm = vo.getStartYm();
        if (startYm == null) {
            startYm = Integer.parseInt(vo.getPeriodYear() + "01");
        }
        Integer endYm = vo.getEndYm();
        if (endYm == null) {
            endYm = Integer.parseInt(vo.getPeriodYear() + "12");
        }
        String operatingName = dictIntegration.getValue("operating", vo.getOperating());
        List<OperationPeriodVO> list = new ArrayList<>();
        while (startYm <= endYm) {
            OperationPeriodVO operationPeriodVO = Convert.convert(OperationPeriodVO.class, vo);
            operationPeriodVO.setYm(startYm);
            DateTime cuDate = DateUtil.parse(startYm + "", "yyyyMM");
            operationPeriodVO.setBegTime(DateUtil.beginOfMonth(cuDate));
            operationPeriodVO.setEndTime(DateUtil.endOfMonth(cuDate));
            operationPeriodVO.setOperatingName(operatingName);
            list.add(operationPeriodVO);
            startYm = startYm + 1;
        }
        return list;
    }

    private void setDict(OperationPeriodVO vo) {
        if (StringUtils.isNotBlank(vo.getOrgId())) {
            vo.setOrgName(dictIntegration.getOrgNameById(vo.getOrgId()));
        }
    }
    /**
     * 获取指定年月的第一天
     *
     * @return
     */
    public Date getFirstDayOfMonth(Integer ym) {
        int year = Integer.parseInt(ym.toString().substring(0, 4));
        int month = Integer.parseInt(ym.toString().substring(5, 6));
        Calendar cal = Calendar.getInstance();
        // 设置年份
        cal.set(Calendar.YEAR, year);
        // 设置月份
        cal.set(Calendar.MONTH, month - 1);
        // 获取某月最小天数
        int firstDay = cal.getMinimum(Calendar.DATE);
        // 设置日历中月份的最小天数
        cal.set(Calendar.DAY_OF_MONTH, firstDay);
        return cal.getTime();
    }

    public Date getLastDayOfMonth(Integer ym) {
        int year = Integer.parseInt(ym.toString().substring(0, 4));
        int month = Integer.parseInt(ym.toString().substring(4, 6));
        Calendar cal = Calendar.getInstance();
        // 设置年份
        cal.set(Calendar.YEAR, year);
        // 设置月份
        cal.set(Calendar.MONTH, month - 1);
        // 获取某月最大天数
        int lastDay = cal.getActualMaximum(Calendar.DATE);
        // 设置日历中月份的最大天数
        cal.set(Calendar.DAY_OF_MONTH, lastDay);

        return cal.getTime();
    }
}
